﻿/*
 * framemodbus.cpp
 *
 *  Created on: 2017年10月31日
 *      Author: Dylan.Gao
 */

#include <dm/export.hpp>

#define DM_API_PROTOCOL DM_API_EXPORT

#include <dm/protocol/framemodbus.hpp>
#include <dm/bytes.hpp>

#include <dm/os/log/logger.hpp>

namespace dm{
namespace protocol{

static const char* logModule = "CFrameModbus.protocol.dm";

CFrameModbus::CFrameModbus():CFrame(),
		m_frameType(FtDn),m_fun(UnknowFunc),m_len(0){
}

CFrameModbus::CFrameModbus( const CFrameModbus& frame ):CFrame(frame),
		m_frameType(frame.m_frameType),m_fun(frame.m_fun),m_len(frame.m_len){
	setData( frame.m_data,frame.m_len );
}

CFrameModbus::~CFrameModbus(){
}

CFrameModbus& CFrameModbus::operator =( const CFrameModbus& frame ){
	m_frameType = frame.m_frameType;
	m_fun = frame.m_fun;
	m_len = frame.m_len;
	setData( frame.m_data,frame.m_len);

	return *this;
}

dm::int8 CFrameModbus::getData_int8( const dm::uint8& offset,const ERegisterSequence& rs )const{
	if( offset>=m_len ){
		log().warnning(THISMODULE "从偏移(%d)获取数据，超出范围(%d)",offset,m_len);
		return 0;
	}

	return dm::byte2int8(m_data[offset]);
}

dm::uint8 CFrameModbus::getData_uint8( const dm::uint8& offset,const ERegisterSequence& rs )const{
	if( offset>=m_len ){
		log().warnning(THISMODULE "从偏移(%d)获取数据，超出范围(%d)",offset,m_len);
		return 0;
	}

	return m_data[offset];
}

dm::int16 CFrameModbus::getData_int16( const dm::uint8& offset,const ERegisterSequence& rs )const{
	if( offset>=m_len || offset+1>=m_len ){
		log().warnning(THISMODULE "从偏移(%d)获取数据，超出范围(%d)",offset,m_len);
		return 0;
	}

	// 高字节在前
	return dm::bytes2int16(m_data[offset+1],m_data[offset]);
}

dm::uint16 CFrameModbus::getData_uint16( const dm::uint8& offset,const ERegisterSequence& rs )const{
	if( offset>=m_len || offset+1>=m_len ){
		log().warnning(THISMODULE "从偏移(%d)获取数据，超出范围(%d)",offset,m_len);
		return 0;
	}

	// 高字节在前
	return dm::bytes2uint16(m_data[offset+1],m_data[offset]);
}

bool CFrameModbus::getData_bit( const int& bit,const dm::uint8& offset )const{
	int byteOffset = getByteOffset(bit);
	if( offset>=m_len || (m_len-offset)<=byteOffset ){
		log().warnning(THISMODULE "从偏移(%d)获取位(%d)数据，超出范围(%d)",offset,bit,m_len);
		return false;
	}

	return 0!=(m_data[offset+byteOffset]&(0x01<<getBitOffset(bit)));
}

/**
 * 用有符号整数设置数据区数据
 * @param c
 * @param offset
 * @return
 */
bool CFrameModbus::setData_int8( const dm::int8& c,const dm::uint8& offset,const ERegisterSequence& rs ){
	if( offset>=m_len ){
		log().warnning(THISMODULE "从偏移(%d)设置数据，超出范围(%d)",offset,m_len);
		return false;
	}

	m_data[offset] = dm::toByte(c);
	return true;
}

bool CFrameModbus::setData_uint8( const dm::uint8& c,const dm::uint8& offset,const ERegisterSequence& rs ){
	if( offset>=m_len ){
		log().warnning(THISMODULE "从偏移(%d)设置数据，超出范围(%d)",offset,m_len);
		return false;
	}

	m_data[offset] = c;
	return true;
}

bool CFrameModbus::setData_int16( const dm::int16& c,const dm::uint8& offset,const ERegisterSequence& rs ){
	if( offset>=m_len || offset+1>=m_len ){
		log().warnning(THISMODULE "从偏移(%d)设置数据，超出范围(%d)",offset,m_len);
		return false;
	}

	m_data[offset] = dm::higByte_i16(c);
	m_data[offset+1] = dm::lowByte_i16(c);

	return true;
}

bool CFrameModbus::setData_uint16( const dm::uint16& c,const dm::uint8& offset,const ERegisterSequence& rs ){
	if( offset>=m_len || offset+1>=m_len ){
		log().warnning(THISMODULE "从偏移(%d)设置数据，超出范围(%d)",offset,m_len);
		return false;
	}

	m_data[offset] = dm::higByte_u16(c);
	m_data[offset+1] = dm::lowByte_u16(c);

	return true;
}

bool CFrameModbus::setData_bit( const bool& set,const int& bit,const dm::uint8& offset ){
	int byteOffset = getByteOffset(bit);
	if( offset>=m_len || (m_len-offset)<=byteOffset ){
		log().warnning(THISMODULE "从偏移(%d)获取位(%d)数据，超出范围(%d)",offset,bit,m_len);
		return false;
	}

	if( set )
		m_data[offset+byteOffset] |= 0x01<<getBitOffset(bit);
	else
		m_data[offset+byteOffset] &= ~(0x01<<getBitOffset(bit));

	return true;
}

bool CFrameModbus::setData( const dm::uint8* buf,const dm::uint8& size,const dm::uint8& offset,const ERegisterSequence& rs ){
	if( offset>=m_len || (m_len-offset)<size ){
		log().warnning(THISMODULE "从偏移(%d)设置%d个数据，超出范围(%d)",offset,size,m_len);
		return false;
	}

	for( dm::uint8 i=0;i<size;++i ){
		m_data[offset+i] = buf[i];
	}

	return true;
}

bool CFrameModbus::setData( const dm::int8* buf,const dm::uint8& size,const dm::uint8& offset,const ERegisterSequence& rs ){
	if( offset>=m_len || (m_len-offset)<size ){
		log().warnning(THISMODULE "从偏移(%d)设置%d个数据，超出范围(%d)",offset,size,m_len);
		return false;
	}

	const dm::uint8* p = (const dm::uint8*)buf;
	for( dm::uint8 i=0;i<size;++i ){
		m_data[offset+i] = p[i];
	}

	return true;
}

bool CFrameModbus::setData( const dm::uint16* buf,const dm::uint8& size,const dm::uint8& offset,const ERegisterSequence& rs ){
	if( offset>=m_len || (offset+1)>=m_len || (m_len-offset-1)<size ){
		log().warnning(THISMODULE "从偏移(%d)设置%d个数据，超出范围(%d)",offset,size,m_len);
		return false;
	}

	// 高字节在前
	for( dm::uint8 i=0;i<size;++i ){
		m_data[offset+i*2] = dm::higByte_u16(buf[i]);
		m_data[offset+i*2+1] = dm::lowByte_u16(buf[i]);
	}

	return true;
}

bool CFrameModbus::setData( const dm::int16* buf,const dm::uint8& size,const dm::uint8& offset,const ERegisterSequence& rs ){
	if( offset>=m_len || (offset+1)>=m_len || (m_len-offset-1)<size ){
		log().warnning(THISMODULE "从偏移(%d)设置%d个数据，超出范围(%d)",offset,size,m_len);
		return false;
	}

	// 高字节在前
	for( dm::uint8 i=0;i<size;++i ){
		m_data[offset+i*2] = dm::higByte_i16(buf[i]);
		m_data[offset+i*2+1] = dm::lowByte_i16(buf[i]);
	}

	return true;
}

void CFrameModbus::setWriteSingleCoil( const dm::uint16& address,const bool& on ){
	setFunc(ForceSigCoil);
	setLen(4);
	setData_uint16(address,0);
	setData_uint16(on?0xFF00:0x0000,2);
}

void CFrameModbus::setWriteSingleRegister( const uint16& address,const uint16& value,const ERegisterSequence& rs ){
	setFunc(PresetSigReg);
	setLen(4);
	setData_uint16(address,0);
	setData_uint16(value,2);
}

void CFrameModbus::setWriteMultipleCoils( const dm::uint16& address,const dm::uint16& quantity ){
	setFunc(ForceMtlCoil);
	setLen(4+1+getBytes(quantity));
	setData_uint16(address,0);
	setData_uint16(quantity,2);
	setData_uint8(getBytes(quantity),4);

	for( dm::uint8 i=5;i<m_len;++i )
		m_data[i] = 0;
}

void CFrameModbus::setWriteMultipleRegisters( const dm::uint16& startAddress,const dm::uint16& quantity ){
	setFunc(PresetMtlReg);
	setLen(4+1+quantity*2);
	setData_uint16(startAddress,0);
	setData_uint16(quantity,2);
	setData_uint8(quantity*2,4);
}

void CFrameModbus::setWriteMultipleRegisters( const dm::uint16& startAddress,const dm::uint16& quantity,const dm::uint16* output,const ERegisterSequence& rs ){
	setWriteMultipleRegisters(startAddress,quantity);
	for( dm::uint16 i=0;i<quantity;++i )
		setWriteMultipleRegistersValue(i,output[i]);
}

void CFrameModbus::setWriteMultipleRegisters( const dm::uint16& startAddress,const dm::uint16& quantity,const dm::uint8* output,const ERegisterSequence& rs ){
	setWriteMultipleRegisters(startAddress,quantity);
	setData(output,quantity*2,5);
}

bool CFrameModbus::getError( EErrCode& errCode )const{
	if( m_frameType==FtUpErr ){
		if( m_len!=1 ){
			log().warnning(THISMODULE "错误帧数据长度(%d)不为1",m_len);
			return false;
		}

		errCode = (EErrCode)m_data[0];
		return true;
	}else{
		return false;
	}
}

bool CFrameModbus::setError( const EErrCode& errCode ){
	if( m_frameType==FtDn ){
		log().warnning(THISMODULE "下行帧不可以设置错误标志");
		return false;
	}else{
		m_frameType = FtUpErr;
		m_len = 1;
		setData_uint8((dm::uint8)errCode);
		return true;
	}
}

void CFrameModbus::clrError(){
	if( m_frameType==FtUpErr )
		m_frameType = FtUp;
}

void CFrameModbus::respone( const CFrameModbus& dnFrame,const EErrCode& errCode ){
	m_fun = dnFrame.m_fun;
	if( errCode!=Err_None ){
		setError(errCode);
	}
}

void CFrameModbus::changeRegisterSequence( dm::uint8& r, const ERegisterSequence& rs ){
	if( rs==Rs_BADC || rs==Rs_DCBA ){
		r = (((r >> 4) | (r<< 4))&0xFF);
	}
}

void CFrameModbus::changeRegisterSequence( dm::uint16& r, const ERegisterSequence& rs ){
	if( rs!=Rs_ABCD ){
		if( rs==Rs_BADC ){
			r = ( (((r>>4)|((r&0xFF00)<<4))&0xFF00) | ( (((r&0x00FF)>>4)|(r<<4))&0x00FF) );
		}else if( rs==Rs_CDAB ){
			r = ( ((r>>8)&0x00FF) | ((r<<8)&0xFF00) );
		}else if( rs==Rs_DCBA ){
			r = ((r>>12)|((r>>8)&0x00F0)|((r>>4)&0x0F00)|(r<<12));
		}
	}
}

bool CFrameModbus::setDnReadCmd( const EFunc& func,const dm::uint16& addr,const dm::uint16& size ){
	setFunc(func);
	setLen(4);
	return setData_uint16(addr,0) &&	setData_uint16(size,2);
}

}
}


